/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package simple.utils.httpclient;


import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.handler.codec.http.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import simple.utils.pool.Pool;

import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 *
 * @author rehak
 */
public class HTTPClientHelper {

    private static final Logger LOGGER = LoggerFactory.getLogger(HTTPClientHelper.class);
    private static final ExecutorService threadPool = Executors.newCachedThreadPool();
    private final DefaultHttpRequest r;

    private HTTPClientHelper(HttpVersion version, HttpMethod method, String uri) {
        r = new DefaultHttpRequest(version, method, uri);
    }

    public static HTTPClientHelper newRequest(HttpVersion version, HttpMethod method, String uri) {
        return new HTTPClientHelper(version, method, uri);
    }

    /**
     * New POST HTTP 1.1 request
     *
     * @param uri
     * @return
     */
    public static HTTPClientHelper newPostRequest(String uri) {
        return new HTTPClientHelper(HttpVersion.HTTP_1_1, HttpMethod.POST, uri);
    }

    /**
     * New GET HTTP 1.1 request
     *
     * @param uri
     * @return
     */
    public static HTTPClientHelper newGetRequest(String uri) {
        return new HTTPClientHelper(HttpVersion.HTTP_1_1, HttpMethod.GET, uri);
    }

    /**
     * Set content
     *
     * @param uri
     * @return
     */
    public HTTPClientHelper content(byte[] content) {
        r.setContent(ChannelBuffers.copiedBuffer(content));
        return addHeader(HttpHeaders.Names.CONTENT_LENGTH, content.length);
    }

    public HTTPClientHelper addHeader(String header, Object value) {
        r.addHeader(header, value);
        return this;
    }

    public DefaultHttpRequest build() {
        return r;
    }

    /**
     * Sends request using supplied client
     *
     * @param client
     * @param timeout
     * @return
     * @throws Exception
     */
    public DefaultHttpResponse send(HTTPClient client, long timeout) throws IOException {
        DefaultHttpResponse re;
        try {
            re = client.send(r, timeout);
        } catch (Exception e) {
            throw new IOException(e);
        }
        if (re != null) {
            return re;
        } else {
            throw new IOException("No response!");
        }
    }

    /**
     * Sends request taking client from supplied pool
     *
     * @param pool
     * @param timeout
     * @return
     * @throws Exception
     */
    public DefaultHttpResponse send(Pool<HTTPClient> pool, long timeout) throws IOException {
        HTTPClient c = null;
        try {
            c = pool.getInstance();
            return send(c, timeout);
        } finally {
            if (c != null) {
                pool.returnInstance(c);
            }
        }
    }

    public void sendAsync(final Pool<HTTPClient> pool, final long timeout, final AsyncResponse<DefaultHttpResponse> response) throws IOException {
        threadPool.submit(new Runnable() {
            @Override
            public void run() {
                try {
                    DefaultHttpResponse send = send(pool, timeout);
                    if (response != null) {
                        response.responseReceived(send);
                    }
                } catch (Exception ex) {
                    LOGGER.error("Some error occured sending proxy setting change", ex);
                    if (response != null) {
                        response.exception(ex);
                    }
                }
            }
        });
    }
}
